/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pt.ipleiria.estg.es1.minesfinder;

import java.util.Random;

/**
 *
 * @author pedro.ferreira
 */
public class CampoMinado {
    
   

    public static final int VAZIO=0;
    /* de 1 a 8 são o número de minas à volta */
    public static final int TAPADO=9;
    public static final int DUVIDA=10;
    public static final int MARCADO=11;
    public static final int REBENTADO=12;
    
    private boolean[][]minas;
    private int[][] estado;
    
    private int largura;
    private int altura;
    private int numMinas;

    private boolean primeiraJogada;
    private Random gerador;
    private boolean jogoTerminado;
    private boolean jogadorDerrotado;
    
    private long instanteInicioJogo; 
    private long duracaoJogo; 
    
    public CampoMinado(int largura, int altura, int numMinas) {
        this.largura = largura;
        this.altura = altura;
        this.numMinas = numMinas;
        minas = new boolean[largura][altura]; // Valores começam a false
        estado = new int[largura][altura]; // Valores começam a 0
        
        for (int x=0; x<largura; x++) {
            for (int y=0; y<altura; y++)
                estado[x][y]=TAPADO;
        }
        primeiraJogada = true;
        gerador = new Random();
        jogoTerminado = false;
        jogadorDerrotado = false;
    }
    
    public int getEstadoQuadricula(int x, int y) {
        return estado[x][y];
    }
 
    public boolean hasMina(int x, int y) {
        return minas[x][y];
    }

    public int getLargura()
    {
        return largura;
    }
    
    public int getAltura()
    {
        return altura;
    }
    
    public boolean isJogoTerminado()
    {
        return jogoTerminado;
    }
    
    public boolean isJogadorDerrotado()
    {
        return jogadorDerrotado;
    }

    public long getDuracaoJogo() {
        if (primeiraJogada) // O jogo ainda não começou         
            return 0;      
        if (!jogoTerminado) // O jogo ainda não terminou         
            return System.currentTimeMillis()-instanteInicioJogo;     
        return duracaoJogo; 
    } 
    
    public void revelarQuadricula(int x, int y) {
        if (estado[x][y] == TAPADO && !jogoTerminado) {
            if (primeiraJogada) {
                primeiraJogada=false;
                colocarMinas(x, y);                
                instanteInicioJogo = System.currentTimeMillis();
            } else if(hasMina(x, y)){
                estado[x][y] = REBENTADO;
                this.jogadorDerrotado = true;
                this.jogoTerminado = true;                
                duracaoJogo = System.currentTimeMillis()-instanteInicioJogo;
            } else {
                int numMinasAVolta = contarMinasAVolta(x, y);
                if(numMinasAVolta==0){
                    estado[x][y] = VAZIO;
                    revelarQuadriculasVizinhas(x,y);
                }
                else
                    estado[x][y] = numMinasAVolta;
                
                if(verificarVitoria()){
                    this.jogoTerminado = true;                
                    this.jogadorDerrotado = false;
                    duracaoJogo = System.currentTimeMillis()-instanteInicioJogo;
                }
            }           
        }                
        
    }
    
    public void marcarComoTendoMina(int x, int y){
        if(estado[x][y] == TAPADO || estado[x][y] == DUVIDA )
            estado[x][y] = MARCADO; 
    }
    
    public void marcarComoSuspeita(int x, int y){
        if(estado[x][y] == TAPADO || estado[x][y] == MARCADO)
            estado[x][y] = DUVIDA; 
    }

    public void desmarcarQuadricula(int x, int y){
        if(estado[x][y] == MARCADO || estado[x][y] == DUVIDA)
            estado[x][y] = TAPADO; 
    }

    
    private void colocarMinas(int exceptoX, int exceptoY) { 
        for (int i=0; i<numMinas; i++) {
            int x=0; 
            int y=0;
            do {
                x=gerador.nextInt(largura);
                y=gerador.nextInt(altura); 
            } while (minas[x][y] || (x==exceptoX && y==exceptoY));
            minas[x][y]=true;
        }
        print();                   
    }

    private int contarMinasAVolta(int x, int y) {
        int resultado=0;
        for (int coluna=Math.max(0, x-1); coluna<Math.min(largura,x+2); coluna++) 
        {
            for (int linha=Math.max(0, y-1); linha<Math.min(altura,y+2); linha++) 
            {
                if (minas[coluna][linha]) {
                   resultado++;
                }
            }
        }
        return resultado-(minas[x][y]?1:0); 
    }

    private void revelarQuadriculasVizinhas(int x, int y) {

        for (int coluna=Math.max(0, x-1); coluna<Math.min(largura,x+2); coluna++) 
        {
            for (int linha=Math.max(0, y-1); linha<Math.min(altura,y+2); linha++) 
            {
                revelarQuadricula(coluna, linha);
            }
        }
    }    
 
    private boolean verificarVitoria() {
        boolean vitoria=true;
        for (int x=0; x<largura; x++) {
            for (int y=0; y<altura; y++) {
                if (!minas[x][y]) {
                    vitoria=vitoria && estado[x][y]>=0 && estado[x][y]<9;
                }
            }
        }
        return vitoria;
    }
    

    private void print()
    {
        for(int x=0; x<largura; x++)
        {
            for(int y=0; y<altura; y++)
            {
                if(minas[y][x])           
                    System.err.print("M ");
                else
                    System.err.print("_ ");
            }
            System.err.print("\n");
        }
    }
    
}
